package com.allwees.bs.module.fms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.allwees.bs.core.modelbase.branch.EBranchType;
import com.allwees.bs.core.modelbase.req.Queryable;
import com.allwees.bs.module.base.service.impl.BoServiceImpl;
import com.allwees.bs.module.core.req.BaseAuditReq;
import com.allwees.bs.module.fms.constant.EAccountLogBsType;
import com.allwees.bs.module.fms.constant.EBalanceType;
import com.allwees.bs.module.fms.dao.PlatformAccountDao;
import com.allwees.bs.module.fms.entity.BaseAccount.WithdrawResult;
import com.allwees.bs.module.fms.entity.PlatformAccount;
import com.allwees.bs.module.fms.entity.PlatformAccountLog;
import com.allwees.bs.module.fms.entity.PlatformWithdrawAccount;
import com.allwees.bs.module.fms.req.ApplyWithdrawReq;
import com.allwees.bs.module.fms.req.AuditWithdrawReq;
import com.allwees.bs.module.fms.req.DoWithdrawReq;
import com.allwees.bs.module.fms.req.ResetWithdrawPasswordReq;
import com.allwees.bs.module.fms.req.SetWithdrawSecurityInfoReq;
import com.allwees.bs.module.fms.service.PlatformAccountLogService;
import com.allwees.bs.module.fms.service.PlatformAccountService;
import com.allwees.bs.module.fms.service.PlatformWithdrawAccountService;
import com.allwees.bs.module.fms.util.FmsNoUtil;
import com.allwees.bs.module.fms.util.WithdrawPasswordVerifier;
import com.allwees.core.common.constant.EStatus;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.List;

/**
 *
 *
 * @author yangylsky
 * @since 2019-12-12
 *
 */
@Service
public class PlatformAccountServiceImpl extends BoServiceImpl<PlatformAccountDao, PlatformAccount> implements PlatformAccountService {
	@Autowired
	private PlatformAccountLogService platformAccountLogService;

	@Autowired
	private PlatformWithdrawAccountService platformWithdrawAccountService;

	@Override
	public boolean create(PlatformAccount account) {
		PlatformAccount existAccount = findDefaultPlatformAccount(account.getBranchUuid());
		Assert.isTrue(StringUtils.isBlank(account.getUuid()), "uuid必须为空");
		Assert.isNull(existAccount, "平台账户已存在");
		account.setAccountNo(FmsNoUtil.genAccountNo(EBranchType.PLATFORM, account.getBranchUuid()));
		return save(account);
	}

	@Override
	public PlatformAccount findDefaultPlatformAccount(String branchUuid) {
		return findUnique(new Queryable<PlatformAccount>() {
			@Override
			public QueryWrapper<PlatformAccount> toQueryWrapper() {
				return new QueryWrapper<PlatformAccount>()
						.eq("branch_uuid", branchUuid);
			}
		});
	}

	@Override
	public boolean setWithdrawSecurityInfo(SetWithdrawSecurityInfoReq req) {
		PlatformAccount account = checkByUuid(req.getAccountUuid());
		Assert.isTrue(StringUtils.isBlank(account.getMobile()), "手机号已经设置");
		Assert.isTrue(StringUtils.isBlank(account.getWithdrawPassword()), "提现密码已经设置");
		account.setMobile(req.getMobile());
		account.setWithdrawPassword(req.getNewPassword());
		return updateByUuid(account);
	}

	@Override
	public boolean resetWithdrawPassword(ResetWithdrawPasswordReq req) {
		PlatformAccount account = checkByUuid(req.getAccountUuid());
		Assert.isTrue(account.isSecurityInfoSet(), "请先绑定手机号和提现密码");
		account.setWithdrawPassword(req.getNewPassword());
		return updateByUuid(account);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean applyWithdraw(ApplyWithdrawReq req) {
		PlatformAccount account = checkByUuid(req.getAccountUuid());
		Assert.isTrue(account.isSecurityInfoSet(), "请先绑定手机号和提现密码");
		Assert.isTrue(account.getMobile().equals(req.getMobile()), "手机号与当前账户绑定手机号不匹配");
		WithdrawPasswordVerifier.verifyPassword(account, req.getPassword());

		WithdrawResult result = account.applyWithdraw(req.getAmount(), req.getCurrency());
		PlatformWithdrawAccount withdrawAccount = platformWithdrawAccountService.checkByUuid(req.getWithdrawAccountUuid());
		logWithdraw(account, withdrawAccount, result);
		return updateByUuid(account);
	}

	private void logWithdraw(PlatformAccount account, PlatformWithdrawAccount withdrawAccount, WithdrawResult result) {
		PlatformAccountLog accountLog = new PlatformAccountLog();
		accountLog.setBalanceType(EBalanceType.OUTGO)
				.setBsType(EAccountLogBsType.WITHDRAW)
				.setNo(FmsNoUtil.genAccountLogNo(account.getBranchUuid(), EBalanceType.OUTGO, EAccountLogBsType.WITHDRAW))
				.setAccountUuid(account.getUuid())
				.setAccountNo(account.getAccountNo())
				.setCounterpartyAccountUuid(withdrawAccount.getUuid())
				.setCounterpartyAccountNo(withdrawAccount.getAccountNo())
				.setTakeAmount(result.getAmount())
				.setCurrency(result.getCurrency())
				.setFee(result.getFee())
				.setBalance(result.getBalance())
				.setBalanceCurrency(result.getBalanceCurrency())
				.setEStatus(EStatus.WAIT_AUDIT);
		platformAccountLogService.create(accountLog);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public int auditWithdraw(AuditWithdrawReq req) {
		List<PlatformAccountLog> accountLogs = platformAccountLogService.findByUuids(req.getAccountLogUuids());
		int succcessNum = 0;
		for(PlatformAccountLog accountLog : accountLogs) {
			if(audit(accountLog, req)) {
				succcessNum++;
			}
		}
		return succcessNum;
	}

	protected boolean audit(PlatformAccountLog accountLog, BaseAuditReq req) {
		Assert.notNull(accountLog, "accountLog must not be null");
		Assert.isTrue(EStatus.WAIT_AUDIT.equals(accountLog.getEStatus()), "当前accountLog状态[" + accountLog.getEStatus() + "]不能执行审核");
		accountLog.setEStatus(req.getResult().status());
		return platformAccountLogService.updateByUuid(accountLog);
	}

	@Override
	public boolean doWithdraw(DoWithdrawReq req) {
		PlatformAccountLog accountLog = platformAccountLogService.findByUuid(req.getWithdrawLogUuid());
		Assert.notNull(accountLog, "流水不能为空");
		Assert.isTrue(EStatus.AUDIT_APPROVED.equals(accountLog.getEStatus()), "流水[" + accountLog.getNo() + "]状态[" + accountLog.getEStatus().desc() + "]不能执行提现");
		accountLog.setEStatus(EStatus.COMPLETED);
		return platformAccountLogService.updateByUuid(accountLog);
	}
}
